/**
 * @file raw_data.c
 *
 * @date Oct 5, 2011
 * @author seth
 *
 * @brief This file is part of EBEX State Estimator, created for the EBEX project
 *
 * This software is copyright (C) 2011 Columbia University
 *
 * EBEX State Estimator is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * EBEX State Estimator is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EBEX State Estimator; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>

#include <log_util.h>
#include <memory_util.h>
#include <data_file.h>
#include <raw_data.h>

void raw_data_close(data_file_t *m_file)
{
	elog(log_level_extreme, "Closing file %s", m_file->filename?m_file->filename:"(Empty Filename)");

	if (m_file->fp) fclose(m_file->fp);
	e_free_quiet(m_file->filename);


	m_file->fp = NULL;
	m_file->filename = NULL;
}

bool raw_data_open(data_file_t *m_file, const char *m_filename, size_t m_offset)
{

	if (!m_file)
	{
		elog(log_level_fatal, "Passed NULL pointer");
		return false;
	}
	if (!m_filename)
	{
		elog(log_level_fatal, "Asked to open NULL filename");
		return false;
	}

	if (!(m_file->fp = fopen(m_filename, m_file->is_sink ? "w" : "r")))
	{
		elog(log_level_fatal, "Could not open %s for %s", m_filename, m_file->is_sink ? "writing" : "reading");
		return false;
	}

	m_file->filename = e_strdup(m_filename);
	m_file->type = DATA_FILE_RAW;
	m_file->stride = 1;
	m_file->offset = m_offset * sizeof(double);

	fseeko(m_file->fp, 0, SEEK_END);
	m_file->num_elements = ftello(m_file->fp) / sizeof(double);

	fseeko(m_file->fp, m_file->offset, SEEK_SET);
	elog(log_level_verbose, "File %s opened with %zu elements.  Setting start to element %zu", m_file->filename, m_file->num_elements, m_offset);

	return true;
}

bool raw_data_reset(data_file_t *m_file)
{

	if (!m_file)
	{
		elog(log_level_fatal, "Passed NULL pointer");
		return false;
	}

	fseeko(m_file->fp, m_file->offset, SEEK_SET);
	elog(log_level_verbose, "File %s reset to starting byte %zu", m_file->filename, m_file->offset);

	return true;
}
/**
 * Fills the data databuffer with packed data (e.g. DIRFILES).  The databuffer will be filled from the current position
 * in the open file and placed in the databuffer at position 
 * @param m_source Pointer to the data source
 * @param m_buffer Offset buffer to receive the data
 * @param m_numelements Number of doubles to insert into the buffer
 * @return Number of elements actually inserted
 */
size_t raw_data_fillbuffer(data_file_t *m_source, double *m_buffer, const size_t m_numelements)
{
	size_t element_to_read = m_numelements;
	size_t elements_read = 0;
	double *databuffer = m_buffer;


	if (m_source->stride == 1)
	{
		elements_read = fread(databuffer, sizeof(double), element_to_read, m_source->fp);
	}
	else
	{
		do
		{
			if (!fread(databuffer++, sizeof(double), 1, m_source->fp))
			{
				break;
			}
			elements_read++;
			fseeko(m_source->fp, sizeof(double) * (m_source->stride - 1), SEEK_CUR);

		} while (--element_to_read && !feof(m_source->fp));
	}

	return elements_read;
}

size_t raw_data_writebuffer(data_file_t *m_source, double *m_buffer, const size_t m_numelements)
{
	elog(log_level_extreme, "Writing %zu elements to %s", m_numelements, m_source->filename?m_source->filename:"(UNK)");
	return fwrite(m_buffer, sizeof(double), m_numelements, m_source->fp);
}

bool raw_data_set_parameters(data_file_t *m_source, const void *m_param)
{
	raw_data_param_t *param = (raw_data_param_t*)m_param;

	m_source->stride = param->stride;

	return true;
}
